package com.tencent.api.statement;

import com.mysql.cj.jdbc.Driver;

import java.sql.*;
import java.util.Properties;
import java.util.Scanner;

/**
 * 目标：
 *      1.明确jdbc的使用流程 和 详细讲解内部设计API的步骤
 *      2.发现问题，引出prepareStatement
 * 需求：
 *      1.输入账号密码
 *      2.进行数据库信息查询（atguigu u_ser)
 *      3.反馈登录成功或者失败
 *基本流程：
 *      1.键盘输入事件，收集账号和密码信息
 *      2.注册驱动
 *      3.获取连接
 *      4.创建Statement
 *      5.发送sql语句，获取结果
 *      6.结果判断，显示登录成功还是失败
 *      7.关闭资源
 */
public class StatementUserLoginPart {
    public static void main(String[] args) throws SQLException, ClassNotFoundException {
        //1.键盘输入事件，收集账号和密码信息
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入账号：");
        String account = scanner.nextLine();
        System.out.println("请输入密码：");
        String password = scanner.nextLine();

        /**
         * 方案1：
         * DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());
         *      问题：注册两次驱动
         *          DriverManager.registerDriver（）方法本身会注册一次
         *          new Driver()注册一次，因为Driver的无参构造函数中有静态代码块，Driver.static{DriverManagger.registerDriver()}
         *      解决：只想注册一次驱动
         *          只触发静态代码块即可 Driver
         *      触发静态代码块：
         *          类加载机制：类加载的时刻，会触发静态代码块
         *                  加载 【class文件->jvm虚拟机的class对象】
         *                  连接 【验证（检查文件类型）->准备（静态变量初始值）->解析（触发静态代码块】
         *                  初始化（静态属性赋真实值）
         *          以下7种方式会触发类加载：
         *              1. new关键字
         *              2. 调用静态属性
         *              3. 调用静态方法
         *              4. 接口 包含1.8 新特性 default关键字
         *              5. 反射 【Class.forName() 类名.class】
         *              6. 子类调用会触发父类的静态代码块
         *              7. 触发类的入口方法main
         *
         */
        //2.注册驱动
        //方法1：两次注册
//        DriverManager.registerDriver(new Driver());

        //方法2：不够优雅  这只能适合于MySQL，oracle不适用，以后换数据库得改代码
//        new Driver();

        //方式3：反射,触发类加载，触发静态静态代码块的调用。字符串可以提取到外部的配置文件，在不改变代码的情况下，完成数据库驱动的切换
        Class.forName("com.mysql.cj.jdbc.Driver");

        /**
         * 重写： 为了子类扩展父类的方法！父类也间接的规范了子类方法的参数和返回！
         * 重载： 重载一般应用在第三方的工具类上，为了方便用户多种方式传递参数形式！简化形式！
         */
        /**
         * 三个参数：
         *    String URL: 连接数据库地址
         *    String user: 连接数据库用户名
         *    String password: 连接数据库用户对应的密码
         * 数据库URL语法：
         *    JDBC:
         *        jdbc:mysql | jdbc:oracle :// 127.0.0.1 | localhost : 3306 / 数据库名
         *        举例：
         *          jdbc:mysql://localhost:3306/day01
         *          jdbc:mysql://192.168.33.45/3306/day01
         *          当前电脑的省略写法！ 注意：本机和端口3306
         *              jdbc:mysql://localhost:3306/day01 = jdbc:mysql:///day01
         *
         * 两个参数：
         *     String URL : 和三个参数的url作用一样。  jdbc:mysql://127.0.0.1:3306/gtguigu
         *     Properties : 就是一个参数封装容器！至少要包含 user / password key!存储连接账号信息！
         *                  properties类似于Map，只不过key=value 都是字符串形式的
         *                  key user : 账号信息
         *                  key password : 密码信息
         * 一个参数：
         *    String URL: URl可以携带目标地址，可以通过?分割，在后面key=value&key=value形式传递参数
         *                jdbc:mysql:///day01?user=root&password=123456
         *                携带固定的参数名 user password 传递账号和密码信息
         * 扩展路径参数(了解):
         *    serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=true
         *
         */
        //3.获取连接
        //三个参数
        Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/atguigu", "root", "1234");

        //两个参数
//        Properties info = new Properties();
//        info.put("uer","root");
//        info.put("password","1234");
//        Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/atguigu", info);
        //一个参数
//        Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/atguigu？user=root&password=1234");

        //4.创建Statement  "小汽车"
        Statement statement = connection.createStatement();

        //5.发送sql语句，获取结果
        //                                                                                                   ' or '1=1  sql注入
        String sql = "select account,PASSWORD,nickname from t_user where account='"+account+"' and PASSWORD='"+password+"';";
        //上面有易错点：sql语句为 ：select account,PASSWORD,nickname from t_user where account='root' and PASSWORD='123456';
        //在用变量平替的时候，单引号不能去掉！！！！！！


        /**
         * SQL分类：DDL(容器创建，修改，删除),DML(插入，修改，删除);DQL(查询);DCL(权限控制)； TPL(事务控制)
         *
         *  ResultSet 结果集对象 = executeQuery(DQL语句)
         *
         *  int       响应行数  = executeUpdate(非DQL语句)
         *          情况1：DML 返回影响的行数
         *          情况2：非DML，返回0
         */
//        int i = statement.executeUpdate(sql);
        ResultSet resultSet = statement.executeQuery(sql);

        /**
         *
         * 你必须有面向对象的思维：Java是面向对象编程的语言 OOP！
         *
         * 1.需要理解ResultSet的数据结构和小海豚查询出来的是一样，需要在脑子里构建结果表！
         * 2.有一个光标指向的操作数据行，默认指向第一行的上边！
         *      我们需要 1.移动光标，指向行，    2.再获取列
         *        1.游标移动问题：
         *        resultSet内部包含一个游标，指定当前数据
         *        默认指在第一行数据之前
         *        boolean = next()
         *              false: 没有数据，也不移动了！
         *              true:  有更多行，并且移动到下一行！
         *       推荐：推荐使用if 或者 while循环，嵌套next方法，循环和判断体内获取数据！
         *       if(next()){获取列的数据！} ||  while(next()){获取列的数据！}
         *
         * 3.获取当前行列的数据！
         *         resultSet.get类型(int columnIndex | String columnLabel)
         *        列名获取  //label 如果没有别名，等于列名， 有别名label就是别名，他就是查询结果的标识！
         *        列的角标  //从左到右 从1开始！ 数据库全是从1开始！
         */
        //6.结果判断，显示登录成功还是失败
//        while (resultSet.next()){
//            //已经指定当前行了
//            int id = resultSet.getInt("id");
//            String account1 = resultSet.getString("account");
//            String password1 = resultSet.getString("PASSWORD");
//            String nickname = resultSet.getString("nickname");
//            System.out.println(id+"  "+account1+"  "+password1+"  "+nickname);
//        }
        //移动一次光标，只要有数据，就代表登录成功
        if(resultSet.next()){
            System.out.println("登录成功！");
        }else {
            System.out.println("登录失败！");
        }

        //7.关闭资源
        resultSet.close();
        statement.close();
        connection.close();
    }
}
